﻿using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.Xsl;
using System.Net;

namespace Huinn.Common.XML
{
    public class XmlHelper
    {
        #region Methods

        /// <summary>
        /// XML Encode
        /// </summary>
        /// <param name="str">String</param>
        /// <returns>Encoded string</returns>
        public static string XmlEncodeAs(string str)
        {
            if (str == null)
                return null;
            str = Regex.Replace(str, @"[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD]", "", RegexOptions.Compiled);
            return XmlEncodeAsIs(str);
        }

        /// <summary>
        /// XML Encode as is
        /// </summary>
        /// <param name="str">String</param>
        /// <returns>Encoded string</returns>
        public static string XmlEncodeAsIs(string str)
        {
            if (str == null)
                return null;
            using (StringWriter sw = new StringWriter())
            using (XmlTextWriter xwr = new XmlTextWriter(sw))
            {
                xwr.WriteString(str);
                String sTmp = sw.ToString();
                return sTmp;
            }
        }

        /// <summary>
        /// Encodes an attribute
        /// </summary>
        /// <param name="str">Attribute</param>
        /// <returns>Encoded attribute</returns>
        public static string XmlEncodeAttribute(string str)
        {
            if (str == null)
                return null;
            str = Regex.Replace(str, @"[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD]", "", RegexOptions.Compiled);
            return XmlEncodeAttributeAsIs(str);
        }

        /// <summary>
        /// Encodes an attribute as is
        /// </summary>
        /// <param name="str">Attribute</param>
        /// <returns>Encoded attribute</returns>
        public static string XmlEncodeAttributeAsIs(string str)
        {
            return XmlEncodeAsIs(str).Replace("\"", "&quot;");
        }

        /// <summary>
        /// Decodes an attribute
        /// </summary>
        /// <param name="str">Attribute</param>
        /// <returns>Decoded attribute</returns>
        public static string XmlDecode(string str)
        {
            var sb = new StringBuilder(str);
            return sb.Replace("&quot;", "\"").Replace("&apos;", "'").Replace("&lt;", "<").Replace("&gt;", ">").Replace("&amp;", "&").ToString();
        }
        /// <summary>
        /// Encodes an attribute
        /// </summary>
        /// <param name="str">Attribute</param>
        /// <returns>Encoded attribute</returns>
        public static string XmlEncode(string str)
        {
            var sb = new StringBuilder(str);
            return sb.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace("'", "&apos;").Replace("\"", "&quot;").ToString();
        }
        /// <summary>
        /// Serializes a datetime
        /// </summary>
        /// <param name="dateTime">Datetime</param>
        /// <returns>Serialized datetime</returns>
        public static string SerializeDateTime(DateTime dateTime)
        {
            var xmlS = new XmlSerializer(typeof(DateTime));
            var sb = new StringBuilder();
            using (StringWriter sw = new StringWriter(sb))
            {
                xmlS.Serialize(sw, dateTime);
                return sb.ToString();
            }
        }

        /// <summary>
        /// Deserializes a datetime
        /// </summary>
        /// <param name="dateTime">Datetime</param>
        /// <returns>Deserialized datetime</returns>
        public static DateTime DeserializeDateTime(string dateTime)
        {
            var xmlS = new XmlSerializer(typeof(DateTime));
            using (StringReader sr = new StringReader(dateTime))
            {
                object test = xmlS.Deserialize(sr);
                return (DateTime)test;
            }
        }

        /// <summary>
        /// Deserializes the given form data given a class type
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="xml">xml string</param>
        /// <returns>deserialized class</returns>
        public static T DeserializeFromXml<T>(string xml)
        {
            T tmp;
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            System.IO.StringReader sr = null;
            try
            {
                sr = new System.IO.StringReader(xml);
                using (XmlTextReader reader = new XmlTextReader(sr))
                {
                    sr = null;
                    tmp = (T)serializer.Deserialize(reader);
                }
            }
            finally
            {
                if (sr != null)
                    sr.Close();
            }
            return tmp;
        }


        /// <summary>
        /// Serializes a class to a string
        /// </summary>
        /// <typeparam name="T">The type of class to be serialized</typeparam>
        /// <param name="data">The instance of the class to serialize</param>
        /// <returns>serialized class</returns>
        public static string SerializeToXml<T>(T data)
        {
            byte[] bytes;
            //Serialize formdata into bytes and return
            using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
            {
                XmlSerializer serializer = new XmlSerializer(typeof(T));
                serializer.Serialize(stream, data);
                stream.Position = 0;
                bytes = new byte[stream.Length];
                stream.Read(bytes, 0, bytes.Length);
            }
            return Encoding.UTF8.GetString(bytes);
        }

        /// <summary>
        /// Initialize Xml
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="rootName"></param>
        /// <returns></returns>
        public static XmlElement InitializeXml(XmlDocument doc, string rootName)
        {
            if (doc == null)
                return null;

            // insert declaration as first element
            XmlDeclaration declaration = doc.CreateXmlDeclaration("1.0", null, "yes");
            doc.InsertBefore(declaration, doc.DocumentElement);

            // insert root element
            XmlElement rootElement = doc.CreateElement(rootName);
            doc.InsertAfter(rootElement, declaration);

            return rootElement;
        }

        /// <summary>
        /// Retrive Xml Document from the specified physical URL
        /// </summary>
        /// <param name="docUrl"></param>
        /// <param name="server"></param>
        /// <returns></returns>
        public static XmlDocument RetrieveXml(string docUrl, System.Web.HttpServerUtility server)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(server.MapPath(docUrl));
            return doc;
        }

        /// <summary>
        /// Retrive Xml Document from the specified web URL
        /// </summary>
        /// <param name="url"></param>
        /// <param name="credentials"></param>
        /// <returns></returns>
        public static XmlDocument RetrieveXmlFromWeb(string url, System.Net.ICredentials credentials)
        {
            XmlDocument xdoc = new XmlDocument();

            // setup request
            HttpWebRequest feed = WebRequest.Create(url) as HttpWebRequest;
            feed.UserAgent = "GetXMLFromWeb";
            feed.Timeout = 60000;
            feed.Method = "GET";
            feed.KeepAlive = false;
            feed.PreAuthenticate = true;
            feed.Credentials = credentials;

            // get response
            HttpWebResponse response = feed.GetResponse() as HttpWebResponse;

            // load response into xml document
            xdoc.Load(response.GetResponseStream());

            return xdoc;
        }

        /// <summary>
        /// Xsl Transform Xml to Html
        /// </summary>
        /// <param name="xmlDoc"></param>
        /// <param name="xsltDoc"></param>
        /// <param name="xsltArgs"></param>
        /// <returns></returns>
        public static string XslTransform(XmlDocument xmlDoc, XmlDocument xsltDoc, XsltArgumentList xsltArgs)
        {
            string html = string.Empty;

            if (xmlDoc == null || xsltDoc == null)
            {
                return html;
            }

            StringBuilder sb = new StringBuilder();
            XslCompiledTransform xs = new XslCompiledTransform();
            XmlUrlResolver resolver = new XmlUrlResolver();
            XsltSettings settings = new XsltSettings(true, true);
            using (System.IO.TextWriter tw = new System.IO.StringWriter(sb))
            {
                resolver.Credentials = System.Net.CredentialCache.DefaultCredentials;
                xs.Load(xsltDoc.CreateNavigator(), settings, resolver);
                xs.Transform(xmlDoc.CreateNavigator(), xsltArgs, tw);
                html = tw.ToString();
            }

            return html;
        }
        #endregion
    }
}
